/**
 * 
 */
package tto.gio.next;


import java.util.List;

import support.Variables;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.telephony.NeighboringCellInfo;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.widget.Toast;

/**
 * @author Mobito
 * 
 */
public class HiddenService extends Service implements LocationListener {

	private static HiddenService mService;
	protected boolean foreground = false;
	protected boolean cancelNotification = false;
	private int notificationId;

	protected Notification foregroundNotification(int notificationId) {
		return getNotification(notificationId);
	}

	public void moveToForeground(int id, boolean cancelNotification) {
		moveToForeground(id, foregroundNotification(id), cancelNotification);
	}

	public void moveToForeground(int id, Notification notification,
			boolean cancelNotification) {
		if (!this.foreground) {
			this.foreground = true;
			this.cancelNotification = cancelNotification;

			super.startForeground(id, notification);
		}
	}

	public void moveToBackground(int id, boolean cancelNotification) {
		foreground = false;

		super.stopForeground(cancelNotification);
	}

	public void moveToBackground(int id) {
		moveToBackground(id, cancelNotification);
	}

	@SuppressWarnings("deprecation")
	public Notification getNotification(int notiID) {
		int icon = R.drawable.ic_launcher;
		CharSequence ticker = "Start Tracer";
		long when = System.currentTimeMillis();
		Notification noti = new Notification(icon, ticker, when);
		noti.flags = noti.flags | Notification.FLAG_ONGOING_EVENT
				| Notification.FLAG_ONLY_ALERT_ONCE;
		noti.setLatestEventInfo(this, getString(R.string.title_notification),
				getString(R.string.message_notification), notificationIntent());

		return noti;

	}

	private PendingIntent notificationIntent() {
		Intent intent = new Intent(this, Terminator.class);

		PendingIntent pending = PendingIntent.getActivity(this, 0, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);

		return pending;
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public void onCreate() {
		StatusManager.GetStatusManager().status
				.InitState(getApplicationContext());
		super.onCreate();

		preLongitude = -1;
		preLatitude = -1;

		requestBestLocation();

		intentFilter = new IntentFilter();
		intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
		intentFilter.addAction("android.location.PROVIDERS_CHANGED");
		intentFilter.addAction(Intent.ACTION_RUN);
		intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
		intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
		intentFilter.addAction(LogReader.APP_INTENT);
		intentFilter.addAction(Monitor.BRIGHTNESS_INTENT);
		intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
		intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
		intentFilter.addAction(Monitor.CELLTOWER_INTENT);

		receiver = new Monitor(getApplicationContext(), this);
		registerReceiver(receiver, intentFilter);

		if (mPower == null)
			mPower = (PowerManager) getSystemService(Context.POWER_SERVICE);
		if (wakeLock == null)
			wakeLock = mPower.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
					"NEXT");

		// to finish service...
		mService = this;
		notificationId = 99999;
		moveToForeground(notificationId, false);
		// mView = new HiddenView(this);

		LogReader.init(this, receiver);
		LogReader.getReader().start();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return START_STICKY;
	}

	@Override
	public void onStart(Intent intent, int startId) {

	}

	@Override
	public void onDestroy() {
		if (wakeLock != null && wakeLock.isHeld())
			wakeLock.release();
		if (locManager != null)
			locManager.removeUpdates(this);

		LogReader.getReader().stop();

		super.onDestroy();
		Toast ts = Toast.makeText(getApplicationContext(), "Service finished",
				Toast.LENGTH_LONG);
		ts.show();

		receiver.onDestroy();
		unregisterReceiver(receiver);

		if (mView != null)
			mView.destory();

		System.exit(0);
	}

	public static void stop() {
		if (mService == null)
			return;
		NotificationManager nm = (NotificationManager) mService
				.getApplicationContext().getSystemService(
						Context.NOTIFICATION_SERVICE);
		nm.cancel(mService.notificationId);
		mService.stopSelf();
		
		Reporter.GetReporter(null).onClose();
		
	}

	// /////////////// LocationListener

	private LocationManager locManager = null;
	private String bestProvider;
	public static boolean USE_GPS_WHEN_ACTIVITY_VISIBLE = true;

	public void requestBestLocation() {
		updateBestProvider(null);
		reloadLocation();
		try {
			onLocationChanged(locManager.getLastKnownLocation(bestProvider));
		} catch (Exception ee) {
			Log.e("tto.gio.next", ee.toString());
			if (Variables.isDebugToastOn) {
				Toast ts = Toast.makeText(getApplicationContext(),
						"loc update error " + ee.toString(), Toast.LENGTH_LONG);
				ts.show();
			}
		}

	}

	public void onLocationChanged(android.location.Location location) {
		int latitude = (int) (location.getLatitude() * 1000000);
		int longitude = (int) (location.getLongitude() * 1000000);
		
		double lon2,lat2;
		if(bestProvider == LocationManager.GPS_PROVIDER)
		{
			LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE); 
			Location loc2 = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			lon2 = loc2.getLongitude();
			lat2 = loc2.getLatitude();
		}
		else
		{
			lon2 = -1;
			lat2 = -1;
		}
		
		
		if (Variables.isDebugToastOn) {
			Toast ts = Toast.makeText(getApplicationContext(), "loc update ",
					Toast.LENGTH_LONG);
			ts.show();
		}
		if (preLatitude == latitude && preLongitude == longitude) {
			return;
		}
		preLatitude = latitude;
		preLongitude = longitude;

		GsmCellLocation cellLocation;
		CdmaCellLocation cdmacell;
		String strNL="";
		
		int cellID=0, lac=0;
		TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		try
		{
			cellLocation = (GsmCellLocation) tm.getCellLocation();
			List<NeighboringCellInfo> nl = tm.getNeighboringCellInfo();
			
			
			if(nl != null){
			for(int i=0; i<nl.size();i++)
				{
					NeighboringCellInfo nci = (NeighboringCellInfo)nl.get(i);
					strNL += nci.getCid() + " "; 
				}
			}
			if(cellLocation != null)
			{
				cellID = cellLocation.getCid();
				lac = cellLocation.getLac();
			}
		}
		catch(Exception ee)
		{
			cdmacell =(CdmaCellLocation) tm.getCellLocation();
			if(cdmacell != null)
			{
				cellID = cdmacell.getBaseStationId();
				lac = cdmacell.getNetworkId();
			} 
		}
		
		if (Variables.isDebugToastOn) {
			Toast ts = Toast.makeText(getApplicationContext(), "Current Cell: "+ cellID
					+ " Neighbor : " + strNL,
					Toast.LENGTH_LONG);
			ts.show();
		}
		
		// Request Cell Location
		//Reporter.GetReporter().RequestCellInfo(getApplicationContext(), cellID, lac);

		StatusManager.GetStatusManager().status.updateLocation(
				location.getLatitude(), location.getLongitude(),
				location.getAccuracy(), location.getSpeed(),cellID, lac);
		
		StatusManager.GetStatusManager().status.updateNetworkLoc(lat2, lon2);
		
		StringBuilder sb = Packet.GetPacket().Update();
		if (sb == null)
			return;
		Reporter.GetReporter(getApplicationContext()).report(sb);
		if (Variables.isToastOn) {
			Toast ts = Toast.makeText(getApplicationContext(), sb.toString(),
					Toast.LENGTH_LONG);
			ts.show();
		}
		wakeLock.acquire(100000);

	}

	public void updateBestProvider(String provider) {
		if (provider == null) {
			LocationManager lm;
			lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
			if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
				bestProvider = "gps";
			} else {
				bestProvider = "network";
			}
		} else
			bestProvider = provider;
	}

	public void reloadLocation() {
		String context = Context.LOCATION_SERVICE;
		/*
		 * Criteria criteria = new Criteria(); if
		 * (USE_GPS_WHEN_ACTIVITY_VISIBLE)
		 * criteria.setAccuracy(Criteria.ACCURACY_FINE); else
		 * criteria.setPowerRequirement(Criteria.POWER_LOW);
		 */
		locManager = (LocationManager) getSystemService(context);
		// bestProvider = locManager.getBestProvider(criteria, false);

		locManager.removeUpdates(this);
		locManager.requestLocationUpdates(bestProvider, 1000, 0, this);
		if (Variables.isDebugToastOn) {
			Toast ts = Toast.makeText(getApplicationContext(),
					"loc update with " + bestProvider, Toast.LENGTH_LONG);
			ts.show();
		}
	}

	public void onProviderDisabled(String provider) {
		updateBestProvider(null);
		reloadLocation();
	}

	public void onProviderEnabled(String provider) {
		updateBestProvider(null);
		reloadLocation();
	}

	public void onStatusChanged(String provider, int status, Bundle extras) {
		reloadLocation();
	}

	/**
	 * Determines whether one Location reading is better than the current
	 * Location fix
	 * 
	 * @param location
	 *            The new Location that you want to evaluate
	 * @param currentBestLocation
	 *            The current Location fix, to which you want to compare the new
	 *            one
	 */
	protected boolean isBetterLocation(Location location,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	// /////////////// LocationListener
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	IntentFilter intentFilter;
	Monitor receiver;
	PowerManager mPower;
	PowerManager.WakeLock wakeLock;
	int preLatitude;
	int preLongitude;
	private HiddenView mView;

}
